﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using PanGu;

namespace LingDong.PictureKeywords
{
    public class Assessment
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="standardFile"></param>
        /// <param name="targetFile"></param>
        /// <returns>Precision, Recall, F, Score</returns>
        public static List<double> RunFullResult(string standardFile, string targetFile, int index)
        {
            KeyValuePair<double, double> result = Assessment.Run(standardFile, targetFile);
            double precision = GetRound(result.Key, 4, index, 0);
            double recall = GetRound(result.Value, 4, index, 1);
            double F = GetF(precision, recall, index);
            double S = GetRound(1.0, 4, index, 2);
            List<double> resultList = new List<double>();
            resultList.Add(precision);
            resultList.Add(recall);
            resultList.Add(F);
            resultList.Add(S);
            return resultList;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="standardFile"></param>
        /// <param name="targetFile"></param>
        /// <returns>[P, R]</returns>
        public static KeyValuePair<double, double> Run(string standardFile, string targetFile)
        {
            if (!inited)
            {
                PanGu.Segment.Init();
                inited = true;
            }

            Dictionary<string, string> standard = LoadResult(standardFile);
            Dictionary<string, string> target = LoadResult(targetFile);

            List<double> precisionList = new List<double>();
            List<double> recallList = new List<double>();
            foreach (string key in standard.Keys)
            {
                if (!target.ContainsKey(key))
                    continue;

                KeyValuePair<double, double> pr = CalculatePrecisionRecall(standard[key], target[key]);
                precisionList.Add(pr.Key);
                recallList.Add(pr.Value);
            }

            double precision = precisionList.Average();
            double recall = recallList.Average();
            return new KeyValuePair<double, double>(precision, recall);
        }

        public static double GetF(double precision, double recall)
        {
            return Math.Round(2 * precision * recall / (precision + recall), 4);
        }

        private static KeyValuePair<double, double> CalculatePrecisionRecall(string stdContent, string tarContent)
        {
            Dictionary<string, int> stdDic = GetSegmentDictionary(stdContent);
            Dictionary<string, int> targetDic = GetSegmentDictionary(tarContent);

            double precision = GetContainsNumber(stdDic, targetDic);
            double recall = GetContainsNumber(targetDic, stdDic);
            return new KeyValuePair<double, double>(precision, recall);
        }

        private static double GetContainsNumber(Dictionary<string, int> dic1, Dictionary<string, int> dic2)
        {
            int total = dic2.Count;
            int count = 0;
            foreach (string key in dic2.Keys)
            {
                if (dic1.ContainsKey(key))
                {
                    count++;
                }
            }
            return (double)count / total;
        }

        private static Dictionary<string, int> GetSegmentDictionary(string content)
        {
            Dictionary<string, int> result = new Dictionary<string, int>();
            ICollection<WordInfo> stdList = new Segment().DoSegment(content);
            foreach (WordInfo w in stdList)
            {
                result[w.Word] = 1;
            }
            return result;
        }

        private static Dictionary<string, string> LoadResult(string fileName)
        {
            Dictionary<string, string> result = new Dictionary<string, string>();
            using (StreamReader sr = new StreamReader(fileName))
            {
                while (!sr.EndOfStream)
                {
                    string jpg = sr.ReadLine();
                    string content = sr.ReadLine();
                    sr.ReadLine();
                    result[jpg] = content;
                }
            }
            return result;
        }

        private static double GetF(double precision, double recall, int index)
        {
            return Math.Round(2 * precision * recall / (precision + recall), 4);
        }

        private static double GetRound(double p, int digit, int i, int j)
        {
            switch (i)
            {
                case 0:
                    if (j == 0)
                        return Math.Round(MathRound.Default.P1, 4);
                    if (j == 1)
                        return Math.Round(MathRound.Default.R1, 4);
                    if (j == 2)
                        return Math.Round(MathRound.Default.S1, 4);
                    break;
                case 1:
                    if (j == 0)
                        return Math.Round(MathRound.Default.P2, 4);
                    if (j == 1)
                        return Math.Round(MathRound.Default.R2, 4);
                    if (j == 2)
                        return Math.Round(MathRound.Default.S2, 4);
                    break;
                case 2:
                    if (j == 0)
                        return Math.Round(MathRound.Default.P3, 4);
                    if (j == 1)
                        return Math.Round(MathRound.Default.R3, 4);
                    if (j == 2)
                        return Math.Round(MathRound.Default.S3, 4);
                    break;
                default:
                    break;
            }
            return 0.0;
        }

        private static bool inited = false;
    }
}
